package xmlcurl

import (
	"errors"
	"github.com/beevik/etree"
)

const (
	errPrefix = "FS mod_cml_curl error: "
)

type XmlConf interface {
	BodyElement() *etree.Element
	MarshalToXml() ([]byte, error)
	UnMarshalFromString(v string) error
	WriteToFile(path string) error
}

type CommonConf struct {
	doc     *etree.Document
	section *etree.Element
}

func (conf *CommonConf) BodyElement() *etree.Element {
	return conf.section
}

func (conf *CommonConf) MarshalToXml() ([]byte, error) {
	conf.doc.Indent(1)
	return conf.doc.WriteToBytes()
}

func (conf *CommonConf) UnMarshalFromString(v string) error {
	if conf.doc == nil {
		conf.doc = etree.NewDocument()
	}
	if err := conf.doc.ReadFromString(v); err != nil {
		return err
	}

	section := conf.doc.FindElement("./document/section")
	if section == nil {
		return errors.New("the element document/section is nil")
	}
	conf.section = section

	return nil
}

func (conf *CommonConf) WriteToFile(path string) error {
	conf.doc.Indent(1)
	return conf.doc.WriteToFile(path)
}

func NewDocument(name string) *etree.Document {
	doc := etree.NewDocument()
	doc.CreateProcInst("xml", `version="1.0" encoding="UTF-8"`)
	document := doc.CreateElement("document")
	document.CreateAttr("type", "freeswitch/xml")

	section := document.CreateElement("section")
	section.CreateAttr("name", name)
	return doc
}

func GetDocument(e *etree.Document) (*etree.Element, error) {
	document := e.SelectElement("document")
	if document == nil {
		return nil, errors.New(errPrefix + "the Element document is nil")
	}
	return document, nil
}

func GetSection(e *etree.Document) (*etree.Element, error) {
	section := e.FindElement("./document/section")
	if section == nil {
		return nil, errors.New(errPrefix + "the Element section is nil")
	}
	return section, nil
}

// NotFound mod_xml_curl 返回 not found
func NotFound() (XmlConf, error) {
	doc := NewDocument("result")
	section, err := GetSection(doc)
	if err != nil {
		return nil, err
	}

	result := section.CreateElement("result")
	result.CreateAttr("status", "not found")
	return &CommonConf{
		doc:     doc,
		section: section,
	}, nil
}
